﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using GodProject.generators;
using GodProject.peoples;
namespace GodProject
{
  /// <summary>
  /// Represents God Fabric
  /// </summary>
  class God : IGod
  {
    #region singleton definition


    /// <summary>
    /// Hided default constructor
    /// </summary>
    private God()
    {
    }

    /// <summary>
    /// Single instance of Fod
    /// </summary>
    private static God _instance;
    /// <summary>
    /// Get's instance of God
    /// </summary>
    public static God Instance
    {
      get { return _instance ?? (_instance = new God()); }
    }
    #endregion singleton definition

    /// <summary>
    /// Generator for human generation by specified rules
    /// </summary>
    private readonly GodPeopleGenerator _generator = new GodPeopleGenerator();

    #region data storing
    /// <summary>
    /// Collection of humans
    /// </summary>
    private readonly List<Human> _humanCollection = new List<Human>();

    #endregion data storing

    #region human creation

    /// <summary>
    /// register human in human's collection
    /// </summary>
    /// <param name="human">human to be registered</param>
    private void Register(Human human)
    {
      _humanCollection.Add(human);
    }

    /// <summary>
    /// Creates human
    /// </summary>
    /// <returns>new human</returns>
    public Human CreateHuman()
    {
      switch (_humanCollection.Count)
      {
        case 0:
        return CreateHuman(Sex.Male);
        case 1:
        return CreateHuman(Sex.Female);
        default:
        return CreateRandomSexHuman();
      }
    }

    /// <summary>
    /// Creates human with random sex
    /// </summary>
    /// <returns>human with random sex</returns>
    private Human CreateRandomSexHuman()
    {
      return _generator.CreateHuman();
    }

    /// <summary>
    /// Creates human by sex
    /// </summary>
    /// <param name="sex">human's sex</param>
    /// <returns>new human</returns>
    public Human CreateHuman(Sex sex)
    {
      Human result = _generator.CreateHuman(sex);
      Register(result);
      return result;
    }

    /// <summary>
    /// Creates human's pair
    /// </summary>
    /// <param name="human">human, for witch pair will be created</param>
    /// <returns>new human</returns>
    public Human CreatePair(Human human)
    {
      Human pair = _generator.CreatePair(human);
      Register(pair);
      return pair;
    }

    #endregion human creation

    #region money calculation
    /// <summary>
    /// Indexator for humans
    /// </summary>
    /// <param name="index">index of human</param>
    /// <returns>money of human on index</returns>
    public double this[int index]
    {
      get
      {
        Human h = _humanCollection[index];
        if (h is CoolParent)
        {
          return (h as CoolParent).Money;
        }
        return 0;
      }
    }

    /// <summary>
    /// Calculates total money count
    /// </summary>
    /// <returns>total money count</returns>
    public double GetTotalMoney()
    {
      return _humanCollection.Select((t, i) => this[i]).Sum();
    }

    /// <summary>
    /// Prints total money to file
    /// </summary>
    public void PrintTotalMoneyToFile()
    {
      using (var writer = new StreamWriter(FileFormat.TotalMoneyFileName))
      {
        writer.WriteLine(FileFormat.TotalMoneyFormat, GetTotalMoney());
      }
    }
  
    #endregion money calculation

  }
}
